Skip to main content
Glama

CJ-MCP

by PoivronMax
仓颉增量引擎相关概念解析.md9 kB
# 增量引擎相关概念解析 > 本文档解析增量引擎中的核心概念,包括 Scope 创建/复用机制、宏展开原理、recache 机制、根装配与冻结窗口等。 **基于**: Cangjie/KoalaRuntime 实现 **核心文件**: `runtime/src/core/StateManagerImpl.cj`, `runtime/src/core/ScopeImpl.cj`, `runtime/src/memoize/visitor.cj` --- ## 目录 1. [Scope 何时创建/复用](#scope-何时创建复用) 2. [宏展开:怎样把普通函数变成"可增量"](#宏展开怎样把普通函数变成可增量) 3. [recache 做了什么](#recache-做了什么) 4. [根装配与冻结窗口](#根装配与冻结窗口) 5. [以创建为例子查看宏展开](#以创建为例子查看宏展开) 6. [某个状态变化(以组件 B 的依赖状态为例)](#某个状态变化以组件-b-的依赖状态为例) 7. [刷新后再次变化(重复增量)](#刷新后再次变化重复增量) 8. [依赖登记要点(读时注册)](#依赖登记要点读时注册) 9. [小结](#小结) --- ## Scope 何时创建/复用 `getMemoScope` 使用“父作用域 + 调用点哈希 id + 参数计数”来定位/创建子作用域: ```328:344:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/StateManagerImpl.cj public func getMemoScope<Value>(id: Hashscopeid, paramCount: Int64): MemoScope<Value> { getMemoScope(id, paramCount, None, None, None, false, None) } ... let new_scope = scope.getChildScope<Value>(id, paramCount, create, compute, cleanup, once, reuseKey) ``` 在父作用域中按 `id` 扫描兄弟链找到可复用的子作用域;未命中则创建并接入链表/树: ```292:345:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/ScopeImpl.cj func getChildScope<V>(...): ScopeImpl<V> { ... while (let Some(child) <- option) { ... if (child.id == id) { this.detachChildScopes(child) this.incremental = child return (child as ScopeImpl<V>).getOrThrow() } } ... let scope = ScopeImpl<V>(id, paramCount, compute, cleanup, reuseKey) scope.manager = this.manager ... this.incremental = scope return scope } ``` ### 宏展开:怎样把普通函数变成“可增量” 通过 `Memo`/`MemoIntrinsic` 宏,编译期对函数进行注入: - 自动添加参数 `(__memo_key: Hashscopeid, manager: StateManagerImpl)`; - 函数体首部获取/创建 `__memo_scope = manager.getMemoScope(...)`; - 将原始形参包为 `State` 参数(`param(index, value)`); - 首次/需要重算时走 `compute → recache`,否则直接 `getCached()`; - 在 return 路径与内联 lambda 中自动插入 `__memo_scope.recache(...)`。 关键注入片段如下: ```173:187:/home/gloria/Cangjie/incremental_runtime/runtime/src/memoize/visitor.cj public override func visit(funcDecl: FuncDecl) { ... funcDecl.funcParams.add(FuncParam(quote(__memo_key: Hashscopeid)), at: 0) funcDecl.funcParams.add(FuncParam(quote(manager: StateManagerImpl)), at: 1) ... funcDecl.block.nodes.add( VarDecl( quote(let __memo_scope = manager.getMemoScope < $(funcType) >(__memo_key + $(CallsiteKey.getCallsiteKey(funcDecl.beginPos.dump().toString())), $(memoizedParams.size))) )) ... } ``` ### recache 做了什么 - 恢复 `manager.currentScope` 回到进入计算前的作用域; - 更新当前作用域的缓存值、`myComputed`、`myModified`、`recomputeNeeded`; - 断开已失效的增量子树 `detachChildScopes(None)`; - 根据本次子节点增量更新统计,驱动父节点的 `incrementalUpdateDone`; - 读取缓存时会将依赖登记到本作用域的 `Dependencies`。 ```416:438:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/ScopeImpl.cj public func recache(newValue: Value): Value { if (!this.isDisposed()) { if(let Some(manager) <- this.manager) { manager.currentScope = this.scopeInternal } } let oldValue = this.myValue this.myValue = newValue this.myModified = this.myComputed && !equalValues(newValue, oldValue.getOrThrow()) this.myComputed = true this.recomputeNeeded = false this.detachChildScopes(None) this.parent?.increment( if (this.nodeAttached.isSome()) { 1 } else { this.nodeCount }, false ) this.nodeAttached?.incrementalUpdateDone(this.parent?.nodeRef ?? None) return this.getCached() } ``` ### 根装配与冻结窗口 根装配通过 `memoRoot → updatableNode` 完成,并在“冻结窗口”内执行 `update`(避免构建阶段推进快照): ```29:33:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/StateManagerImpl.cj public func memoRoot<Node>(node: Node, update: (StateManagerImpl) -> Unit): ComputableState<Node> where Node <: IncrementalNode { let manager = GlobalStateManager.instance() manager.updatableNode(node, { => manager.runWithFrozen(update)}, None) } ``` ```165:183:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/StateManagerImpl.cj public func updatableNode<Node>(node: Node, update: () -> Unit, cleanup: ?() -> Unit): ComputableState<Node> where Node <: IncrementalNode { ... let scope = ScopeImpl<Node>( None, 2, { => update(); node }, {_ => cleanup?()}, None ) scope.manager = this scope.nodeAttached = node scope.nodeRef = node ... return scope } ``` ```55:60:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/StateManagerImpl.cj func runWithFrozen(runnable: (StateManagerImpl) -> Unit): Unit { let old = frozen frozen = true runnable(this) frozen = old } ``` ### 以创建为例子查看宏展开 冻结窗口内执行 `update`,组件 A、B 的被注入函数体: - 注入 `__memo_key` 与 `manager`; - 首部 `__memo_scope = manager.getMemoScope(...)`; - 形参通过 `param()` 转为 `State`,读取将登记依赖; - 首次进入 `scope.isUnchanged() == false`,走 `compute → recache` 完成缓存与节点接入。 示例(多参 `memoN` 的公共形态): ```48:56:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/memo.cj let scope = manager.getMemoScope<Value>(_new_id, 2, None, None, None, false, None) let s1 = scope.param(0, p1) let s2 = scope.param(1, p2) if (scope.isUnchanged()) { scope.getCached() } else { scope.recache(compute(s1, s2)) } ``` ### 某个状态变化(以组件 B 的依赖状态为例) 1) 写入状态: ```104:118:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/StateImpl.cj public func setValue(value: Value) { ... this.updated = false if (let Some(manager) <- this.manager) { manager.updateNeeded = true } else { this.updateStateSnapshot() } } ``` 2) 触发快照推进: ```37:40:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/GlobalStateManager.cj public func updateStateManager(...): Unit { manager.updateSnapshot() } ``` 3) 在 `updateSnapshot` 中: - 先 diff 所有 `createdStates`; - 消费 `dirtyScopes`,对受影响作用域 `scope.isModified()`,必要时重算; ```134:163:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/StateManagerImpl.cj public func updateSnapshot(): UInt64 { ... } ``` 4) 脏标记如何产生:参数/作用域调用 `invalidate()`,自下而上标记 `recomputeNeeded = true`,到达顶层且有依赖时加入 `dirtyScopes`: ```240:263:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/ScopeImpl.cj public func invalidate(): Unit { ... manager.addDirtyScope(scope) ... } ``` ### 刷新后再次变化(重复增量) 后续任意一次状态变化,重复“标记需要更新 → updateSnapshot → 仅重算脏作用域”。未变化子树由 `IncrementalNode.incrementalUpdateSkip(count)` 快速跳过: ```155:173:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/IncrementalNode.cj func incrementalUpdateSkip(count: UInt32) { ... } ``` ### 依赖登记要点(读时注册) - 作用域缓存读取: ```409:414:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/ScopeImpl.cj public func getCached(): Value { this.dependencies?.onUpdate(this.myModified); this.myValue.getOrThrow() } ``` - State 读取: ```80:84:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/StateImpl.cj private func onAccess(): Unit { ... this.dependencies?.register(dep) } ``` - 参数读取: ```45:50:/home/gloria/Cangjie/incremental_runtime/runtime/src/core/ParameterImpl.cj public func getValue(): Value { ... this.dependencies?.register(dep) ; return this.value } ``` ### 小结 - 宏把普通函数转为“有作用域、可追踪依赖、可缓存”的增量函数; - 作用域以调用点为键在父-子关系中创建/复用,`recache` 负责值更新、子树维护与节点接入; - 状态写入只置位 `updateNeeded`,实际比较与作用域重算发生在 `updateSnapshot()`; - 未变更部分通过节点级“跳过”实现高效增量,整体更新最小化。

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/PoivronMax/idlize-cj-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server